package com.es.www.kyl.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.es.www.kyl.bean.req.client.QuestionCompletionReq;
import com.es.www.kyl.bean.req.web.QuestionAddReq;
import com.es.www.kyl.bean.req.web.QuestionAuditReq;
import com.es.www.kyl.bean.req.web.QuestionReq;
import com.es.www.kyl.bean.req.web.QuestionUpdateReq;
import com.es.www.kyl.bean.res.client.QuestionCompletionVO;
import com.es.www.kyl.bean.res.web.QuestionListVO;
import com.es.www.kyl.constant.BaseConstants;
import com.es.www.kyl.domain.*;
import com.es.www.kyl.exception.ResException;
import com.es.www.kyl.mapper.*;
import com.es.www.kyl.service.QuestionService;
import com.es.www.kyl.service.mapstruct.CategoryMapConstruct;
import com.es.www.kyl.service.mapstruct.QuestionAnalysisMapConstruct;
import com.es.www.kyl.service.mapstruct.QuestionMapConstruct;
import com.es.www.kyl.service.mapstruct.QuestionOptionMapConstruct;
import com.es.www.kyl.util.UserContextHolder;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @createDate 2023-04-01 14:12:08
 */
@Service
@RequiredArgsConstructor
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService {


    private final QuestionMapper questionMapper;
    private final QuestionAnalysisMapper questionAnalysisMapper;
    private final QuestionOptionMapper questionOptionMapper;
    private final CategoryMapper categoryMapper;
    private final UserPracticeStateMapper userPracticeStateMapper;
    private final UserAnswerLogMapper userAnswerLogMapper;

    @Override
    public PageInfo<QuestionListVO> pageQueryQuestionList(QuestionReq req) {
        PageHelper.startPage(req.getPageNum(), req.getPageSize());
        List<QuestionListVO> list = questionMapper.selectQuestionList(req);
        list.forEach(question -> {
            //查询一级分类id
            Category category = categoryMapper.selectById(question.getSecondCategoryId());
            question.setFirstCategoryId(category.getParentId());
            //查询选项
            List<QuestionOption> questionOptions = questionOptionMapper.selectList(new LambdaQueryWrapper<QuestionOption>()
                    .eq(QuestionOption::getQuestionId, question.getId()));
            if (CollectionUtils.isNotEmpty(questionOptions)) {
                question.setQuestionOptionList(QuestionOptionMapConstruct.INSTANCE.toQuestionOptionVOList(questionOptions));
            }
            //查询解析
            List<QuestionAnalysis> questionAnalysisList = questionAnalysisMapper.selectList(new LambdaQueryWrapper<QuestionAnalysis>()
                    .eq(QuestionAnalysis::getQuestionId, question.getId()));
            question.setAnalysisList(QuestionAnalysisMapConstruct.INSTANCE.toQuestionAnalysisVOList(questionAnalysisList));
        });
        return new PageInfo<>(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addQuestion(QuestionAddReq req) {
        if (!UserContextHolder.isVipOrAdmin()) {
            throw new ResException("无发布权限");
        }
        Question question = QuestionMapConstruct.INSTANCE.toQuestion(req);
        //list转换为逗号分割的字符串
        if (CollectionUtils.isNotEmpty(req.getVideoList())) {
            question.setQuestionVideo(String.join(",", req.getVideoList()));
        }
        if (CollectionUtils.isNotEmpty(req.getImageList())) {
            question.setQuestionImage(String.join(",", req.getImageList()));
        }
        question.setCreateBy(UserContextHolder.getUserId());
        question.setCreateTime(new Date());
        questionMapper.insertSelective(question);
        //新增选项/答案
        req.getOptionList().forEach(option -> {
            QuestionOption questionOption = new QuestionOption();
            questionOption.setQuestionId(question.getId());
            questionOption.setOptionContent(option.getOptionContent());
            questionOption.setCorrectFlag(option.getCorrectFlag());
            questionOption.setSort(option.getSort());
            questionOption.setCreateBy(UserContextHolder.getUserId());
            questionOption.setCreateTime(new Date());
            questionOptionMapper.insertSelective(questionOption);
        });
        //新增解析
        req.getAnalysisList().forEach(analysis -> {
            QuestionAnalysis questionAnalysis = new QuestionAnalysis();
            questionAnalysis.setQuestionId(question.getId());
            questionAnalysis.setContent(analysis.getContent());
            questionAnalysis.setType(analysis.getType());
            questionAnalysis.setSort(analysis.getSort());
            questionAnalysis.setCreateBy(UserContextHolder.getUserId());
            questionAnalysis.setCreateTime(new Date());
            questionAnalysisMapper.insertSelective(questionAnalysis);
        });
    }

    @Override
    public void deleteQuestion(Integer questionId) {
        if (!UserContextHolder.isSuperAdmin()) {
            throw new ResException("仅超管可删除题目");
        }
        questionMapper.deleteById(questionId);
        questionOptionMapper.delete(new LambdaQueryWrapper<QuestionOption>().eq(QuestionOption::getQuestionId, questionId));
        questionAnalysisMapper.delete(new LambdaQueryWrapper<QuestionAnalysis>().eq(QuestionAnalysis::getQuestionId, questionId));
    }

    @Override
    public void auditQuestion(QuestionAuditReq req) {
        if (!UserContextHolder.isSuperAdmin()) {
            throw new ResException("仅超管可删除题目");
        }
        Question question = questionMapper.selectById(req.getQuestionId());
        if (Objects.isNull(question)) {
            throw new ResException("题目不存在");
        }
        question.setStatus(req.getStatus());
        question.setUpdateBy(UserContextHolder.getUserId());
        question.setUpdateTime(new Date());
        questionMapper.updateById(question);
    }

    @Override
    public List<QuestionCompletionVO> getQuestionCompletionList(QuestionCompletionReq req) {
        List<Category> categoryList = categoryMapper.selectList(new LambdaQueryWrapper<Category>()
                .eq(Category::getParentId, req.getCategoryId())
                .orderByAsc(Category::getSort)
        );

        if (Objects.isNull(req.getUserId())) {
            //游客模式
            return CategoryMapConstruct.INSTANCE.toQuestionCompletionVOList(categoryList);
        }

        return categoryList.stream().map(category -> {
            QuestionCompletionVO questionCompletion = new QuestionCompletionVO();
            questionCompletion.setCategoryId(category.getId());
            questionCompletion.setCategoryName(category.getName());
            questionCompletion.setStyle(category.getStyle());

            //查询用户练习状态
            List<UserPracticeState> userPracticeStateList = userPracticeStateMapper.selectUserPracticeStateListGroupByPracticeType(req.getUserId(), category.getId());
            List<QuestionCompletionVO.UserPracticeStateVO> userPracticeStateVOList = userPracticeStateList.stream().map(userPracticeState -> {
                QuestionCompletionVO.UserPracticeStateVO userPracticeStateVO = new QuestionCompletionVO.UserPracticeStateVO();
                userPracticeStateVO.setRoundId(userPracticeState.getRoundId());
                userPracticeStateVO.setStatus(userPracticeState.getStatus());
                userPracticeStateVO.setPracticeType(userPracticeState.getPracticeType());
                return userPracticeStateVO;
            }).collect(Collectors.toList());
            questionCompletion.setUserPracticeStateList(userPracticeStateVOList);

            //普通练习
            Optional<UserPracticeState> commonUserPracticeStateOptional = userPracticeStateList.stream().filter(userPracticeState -> Objects.equals(userPracticeState.getPracticeType(), BaseConstants.UserPracticeType.COMMON.getType())).findFirst();
            buildQuestionCompletion(questionCompletion, commonUserPracticeStateOptional, req.getUserId(), category.getId());

            //查询有无错题记录
            questionCompletion.setHasWrongFlag(buildHasWrongFlag(commonUserPracticeStateOptional, req.getUserId(), category.getId()));
            return questionCompletion;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateQuestion(QuestionUpdateReq req) {
        if (!UserContextHolder.isVipOrAdmin()) {
            throw new ResException("无更新权限");
        }
        // 检查题目是否存在
        Question oldQuestion = questionMapper.selectById(req.getQuestionId());
        if (Objects.isNull(oldQuestion)) {
            throw new ResException("题目不存在");
        }
        // 更新题目基本信息
        Question question = new Question();
        question.setId(req.getQuestionId());
        question.setCategoryId(req.getCategoryId());
        question.setTitle(req.getTitle());
        question.setType(req.getType());
        // 将list转换为逗号分割的字符串
        if (CollectionUtils.isNotEmpty(req.getVideoList())) {
            question.setQuestionVideo(String.join(",", req.getVideoList()));
        }
        if (CollectionUtils.isNotEmpty(req.getImageList())) {
            question.setQuestionImage(String.join(",", req.getImageList()));
        }
        question.setUpdateBy(UserContextHolder.getUserId());
        question.setUpdateTime(new Date());
        questionMapper.updateById(question);

        // 删除原有的选项和解析
        questionOptionMapper.delete(new LambdaQueryWrapper<QuestionOption>()
                .eq(QuestionOption::getQuestionId, req.getQuestionId()));
        questionAnalysisMapper.delete(new LambdaQueryWrapper<QuestionAnalysis>()
                .eq(QuestionAnalysis::getQuestionId, req.getQuestionId()));
        
        // 新增选项
        req.getOptionList().forEach(option -> {
            QuestionOption questionOption = new QuestionOption();
            questionOption.setQuestionId(req.getQuestionId());
            questionOption.setOptionContent(option.getOptionContent());
            questionOption.setCorrectFlag(option.getCorrectFlag());
            questionOption.setSort(option.getSort());
            questionOption.setCreateBy(UserContextHolder.getUserId());
            questionOption.setCreateTime(new Date());
            questionOptionMapper.insertSelective(questionOption);
        });
        
        // 新增解析
        req.getAnalysisList().forEach(analysis -> {
            QuestionAnalysis questionAnalysis = new QuestionAnalysis();
            questionAnalysis.setQuestionId(req.getQuestionId());
            questionAnalysis.setContent(analysis.getContent());
            questionAnalysis.setType(analysis.getType());
            questionAnalysis.setSort(analysis.getSort());
            questionAnalysis.setCreateBy(UserContextHolder.getUserId());
            questionAnalysis.setCreateTime(new Date());
            questionAnalysisMapper.insertSelective(questionAnalysis);
        });
    }

    private Boolean buildHasWrongFlag(Optional<UserPracticeState> commonUserPracticeStateOptional, Integer userId, Integer categoryId) {
        if (commonUserPracticeStateOptional.isPresent()) {
            //查询错题记录
            Long wrongCount = userAnswerLogMapper.selectCount(new LambdaQueryWrapper<UserAnswerLog>()
                    .eq(UserAnswerLog::getUserId, userId)
                    .eq(UserAnswerLog::getCategoryId, categoryId)
                    .eq(UserAnswerLog::getCorrectFlag, 0)
                    .eq(UserAnswerLog::getRoundId, commonUserPracticeStateOptional.get().getRoundId())
            );
            return wrongCount > 0;
        }
        return false;
    }

    private void buildQuestionCompletion(QuestionCompletionVO questionCompletion,
                                         Optional<UserPracticeState> commonUserPracticeStateOptional,
                                         Integer userId,
                                         Integer categoryId) {
        // 如果普通练习为空，表示本轮用户还没有开始练习，设置默认值
        if (!commonUserPracticeStateOptional.isPresent()) {
            questionCompletion.setCompletionRate("0.00%");
            questionCompletion.setCorrectRate("0.00%");
        } else {
            UserPracticeState commonUserPracticeState = commonUserPracticeStateOptional.get();
            //本轮总题目数
            Integer totalCount = commonUserPracticeState.getRoundQuestionCount();
            //答题记录
            List<UserAnswerLog> userAnswerLogList = userAnswerLogMapper.selectList(new LambdaQueryWrapper<UserAnswerLog>()
                    .eq(UserAnswerLog::getUserId, userId)
                    .eq(UserAnswerLog::getCategoryId, categoryId)
                    .eq(UserAnswerLog::getRoundId, commonUserPracticeState.getRoundId())
            );

            // 已答题目数量和答题正确的数量
            int answeredCount = userAnswerLogList.size();
            long correctCount = userAnswerLogList.stream().filter(UserAnswerLog::getCorrectFlag).count();
            // 计算完成度
            String completionRate = "0.00%";
            if (totalCount != null && totalCount > 0) {
                completionRate = String.format("%.2f%%", (answeredCount * 100.0) / totalCount);
            }
            questionCompletion.setCompletionRate(completionRate);
            // 计算正确率
            String correctRate = "0.00%";
            if (answeredCount > 0) {
                correctRate = String.format("%.2f%%", (correctCount * 100.0) / answeredCount);
            }
            questionCompletion.setCorrectRate(correctRate);
        }
    }
}